﻿using AForge.Video;
using AForge.Video.DirectShow;
using AntdUI;
using DB;
using Models;
using Newtonsoft.Json.Linq;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using ZXing;
using ZXing.QrCode.Internal;

namespace Elixi_AntdUi
{
    public partial class MainWindow_In : AntdUI.Window
    {
        private AntdUI.Window window;
        AntList<Tb_UsersInfo> antList_userinfo;
        Tb_UsersInfo curTb_UsersInfo;

        //关联GUID
        string tB_Clothes_GUID = string.Empty;
        // 记录登录状态
        private bool _isLoggedIn = false;
        //
        string _username = string.Empty;
        string _userguid = string.Empty;
        string _userpassword = string.Empty;
        // 记录登录状态
        public string ColumnWidths = "100,150,200";
        // 定义公共属性用于接收用户名
        public string LoginUserName { get; set; }
        string lastsensorid1 = string.Empty;
        string lastsensorid2 = string.Empty;



        #region 视频类
        // 变量，允许动态修改:帧率和识别参数
        private int VideoMaxFPS;  // 最大帧率限制
        private  int VideoMinFPS ; // 最小帧率限制
        private  int VideoMaxOrMinFPS ;  

        // 视频设备集合
        private FilterInfoCollection videoDevices;
        //视频设备是否在运行
        private bool isCameraRunning = false;
        // 当前使用的视频捕获设备
        private VideoCaptureDevice videoSource;
        // 条形码读取器实例
        private readonly BarcodeReader barcodeReader;
        // 标记是否已扫描到条形码
        private bool isBarcodeScanned = false;
        // 标记停止操作是否正在进行
        private bool isStopping = false;
        // 用于居中显示图像的Bitmap
        private Bitmap centeredBitmap;
        // 用于窗体关闭的取消令牌
        private CancellationTokenSource formClosingCts;

        // 【新增】图像操作线程安全锁（解决多线程资源冲突）
        private readonly object _cameraImageLock = new object();

        // 性能优化变量
        private DateTime lastDecodeTime = DateTime.MinValue;
        private const int MIN_DECODE_INTERVAL = 500; // 最小识别间隔(毫秒)
        private bool isProcessingFrame = false;
        private Bitmap lastProcessedFrame;
        private DateTime lastFrameTime = DateTime.MinValue;


        //用于记录信息核验
        private bool isCheck = false;
        #endregion


        #region Config类
        // 当前应用程序配置
        private AppConfig _currentConfig;

        // 配置锁对象，确保多线程安全访问配置
        private readonly object _configLock = new object();

        // 文件系统监视器，用于监控配置文件变化
        private FileSystemWatcher _fileWatcher;

        // 配置文件路径（默认为应用程序目录下的config.json）
        private const string ConfigPath = "config.json";

        #endregion


        #region 读卡器相关变量/窗体传输

        private bool isReaderRunning = false;
        // 全局变量：存储HFReader实例（确保整个Form1生命周期可访问）
        private HFReader hFReaderInstance;
        private SelectRFID _SelectRFID;
        // （可选）定义有效传感器ID的匹配规则（与HFReader内部ParseSensorData规则一致，确保解析逻辑统一）
        private const string SensorIdPattern = @"E[0-9A-Fa-f]{15}"; // E开头+15位十六进制（共16位）
        #endregion 

        public MainWindow_In()
        {
            InitializeComponent();

            //加载配置并存储核心数据到变量
            LoadConfigAndInitData();

            //初始化表格列头
            InitTableColumns();
            //数据
            dataGridView_table_data();


            #region  图像
            //获取帧率
            VideoFPS();
            //磁盘监控
            CheckDiskSpace();
            //在应用启动时添加定时清理任务
            ScheduleLogCleanup();

            // 初始化条形码阅读器
            barcodeReader = new BarcodeReader
            {
                // 自动旋转图像以识别不同方向的条码
                AutoRotate = true,

                // 设置只识别一维条码（商品条码）
                Options =
                {
                    /*PossibleFormats = new[] { BarcodeFormat.All_1D },
                    TryHarder = false // 关闭复杂模式以提高性能*/
                    // 1. 指定吊牌常见格式（缩小识别范围，提升速度）
                PossibleFormats = new List<BarcodeFormat>
                {
                   // BarcodeFormat.EAN_13,  // 商品条码（最常见）
                    BarcodeFormat.CODE_128, // 物流/吊牌扩展条码
                    //BarcodeFormat.CODE_39  // 部分品牌使用
                },
                // 2. 抗干扰配置（吊牌可能有褶皱、反光）
               
                TryHarder = true,       // 投入更多计算资源识别
                PureBarcode = true,    // 允许条码周围有干扰（如吊牌底色、文字）
                CharacterSet = "UTF-8"  // 支持中文（如有）
                }
            };


            // 订阅窗体事件
            this.FormClosing += Form1_FormClosing;
            this.Resize += Form1_Resize;

            // 初始化取消令牌源
            formClosingCts = new CancellationTokenSource();


            // 检测所有可用的视频输入设备
            videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);

            // 如果没有检测到摄像头设备
            if (videoDevices.Count == 0)
            {
                MessageBox.Show("未检测到可用摄像头。请连接摄像头后重启应用。",
                                "设备错误",
                                MessageBoxButtons.OK,
                                MessageBoxIcon.Error);
                btn_cam_start.Enabled = false; // 禁用开始按钮
                return;
            }

            // 将检测到的摄像头添加到下拉列表
            foreach (FilterInfo device in videoDevices)
            {
                cmbCamera.Items.Add(device.Name);
            }

            // 默认选择第一个摄像头
            cmbCamera.SelectedIndex = 0;

            // 初始化状态标签
            lblStatus.Text = "就绪";
            lblStatus.ForeColor = Color.Green;

            #endregion 图像

            //初始化提示信息
            button_ShowMess_Mes(AntdUI.TTypeMini.Default, "初始化");

            // 记录窗体初始化
            Log4.Info("System/Startup", "主窗体初始化完成");
            Console.Write("System/Startup", "主窗体初始化完成");
        }

        private void MainWindow_Load(object sender, EventArgs e)
        {

            //自启动
            AutoStartCamAndRead();

        }
        /// <summary>
        /// 视频帧率
        /// </summary>
        public  void VideoFPS()
        {
            // 加载配置文件
            var currentConfig = AppConfig.LoadConfig();
        
            if (currentConfig.AllConfig.VideoMinFPS < currentConfig.AllConfig.VideoMaxFPS  && currentConfig.AllConfig.VideoMinFPS >1)
            {
                VideoMinFPS = currentConfig?.AllConfig?.VideoMinFPS ?? 15;
                VideoMaxFPS = currentConfig?.AllConfig?.VideoMaxFPS ?? 30;
                VideoMaxOrMinFPS = VideoMaxFPS;
            }
            else
            {
                VideoMinFPS = 15;
                VideoMaxFPS = 30;
                VideoMaxOrMinFPS = VideoMaxFPS;
            }

        }

        /// <summary>
        /// 按钮调出新窗体
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_Select_Click(object sender, EventArgs e)
        {

            SelectRFID selectForm = new SelectRFID();
            selectForm.ShowDialog(); // 使用ShowDialog代替Show


            Console.WriteLine("[SelectRFID] 显示SelectRFID实例");

        }


        /// <summary>
        /// 打开/复用HFReader（Form2）的按钮点击事件
        /// 修复点：1. 保留原有实例复用逻辑；2. 新增Form1关闭时同步关闭Form2的逻辑；3. 修复Hide()方法空引用错误
        /// </summary>
        private void btn_StartRead_Click(object sender, EventArgs e)
        {
            // 1. 实例创建/复用（保留你的原有逻辑，确保重新打开时订阅事件）
            if (hFReaderInstance == null || hFReaderInstance.IsDisposed)
            {
                hFReaderInstance = new HFReader();

                //设置主窗体为从窗体的所有者（不影响前台切换，仅优化窗口管理）
                // 保留所有者关系，便于Form2反向访问Form1
                hFReaderInstance.Owner = this;

                // 禁用置顶（默认就是false，显式设置更保险）
                hFReaderInstance.TopMost = false;

                // 订阅数据推送事件（使用独立方法，避免闭包导致解绑困难）
                hFReaderInstance.DataUpdated += OnForm2DataUpdated;

                // 修复1：Form2关闭时改为“真正关闭”，避免隐藏导致的实例残留
                hFReaderInstance.FormClosing += (s, args) =>
                {
                    // 将sender转换为HFReader实例，避免直接使用hFReaderInstance字段
                    var form2 = s as HFReader;
                    if (form2 == null) return; // 确保实例有效

                    // 关键：区分“Form1主动关闭”和“Form2单独关闭”
                    if (this.IsDisposed) // 若Form1已关闭，Form2必须同步关闭
                    {
                        args.Cancel = false; // 允许关闭
                        form2.DataUpdated -= OnForm2DataUpdated; // 解绑事件
                        Console.WriteLine("[Form1] Form1已关闭，Form2同步关闭并解绑事件");
                    }
                    else // 若Form1未关闭，Form2关闭时改为隐藏（保留复用能力）
                    {
                        args.Cancel = true; // 取消默认关闭
                        form2.Hide(); // 使用转换后的实例，避免空引用
                        Console.WriteLine("[Form1] Form2关闭改为隐藏，保留实例用于下次复用");
                    }
                };

                // 修复2：Form2真正关闭时（如调用Close()），彻底清理引用
                hFReaderInstance.FormClosed += (s, args) =>
                {
                    var form2 = s as HFReader;
                    if (form2 != null)
                    {
                        form2.DataUpdated -= OnForm2DataUpdated; // 解绑事件（关键：避免内存泄漏）
                    }
                    hFReaderInstance = null; // 清空实例引用，允许GC回收
                    Console.WriteLine("[Form1] Form2已彻底关闭，清空实例引用");
                };
            }

            // 显示Form2（隐藏状态则重新显示，不重复创建）
            hFReaderInstance.Show();
            Console.WriteLine("[Form1] 显示HFReader实例（新创建/隐藏后重新显示）");
        }




        /// <summary>
        /// 关闭读卡器
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_StopRead_Click(object sender, EventArgs e)
        {

            if (hFReaderInstance != null && !hFReaderInstance.IsDisposed)
            {
                // 显示Form2（隐藏状态则重新显示，不重复创建）
                hFReaderInstance.Hide();
                Console.WriteLine("[Form1] 显示HFReader实例（新创建/隐藏后重新显示）");
                //hFReaderInstance.Show(); // 显示隐藏的Form2
            }
            else
            {
                //hFReaderInstance.Show(); // 显示隐藏的Form2

                MessageBox.Show("Form2未打开");
            }
        }

        /// <summary>
        /// 摄像头关闭按钮事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void btn_cam_stop_Click(object sender, EventArgs e)
        {
            // 禁用停止按钮避免多次点击
            btn_cam_stop.Enabled = false;
            btn_cam_start.Enabled = true;

            await StopCameraAsync();
        }

        /// <summary>
        /// 摄像头开启
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void btn_cam_start_Click(object sender, EventArgs e)
        {
            #region   校验当前用户信息

            if (string.IsNullOrWhiteSpace(_userguid) || string.IsNullOrWhiteSpace(_username))
            {
                MessageBox.Show($"当前用户信息不准确，需重新登录，UserName：{_username},UserID：{_userguid},");
                return;
            }

            #endregion

            // 确保有可用设备
            if (videoDevices == null || videoDevices.Count == 0) return;

            // 重置扫描状态
            txtBarcode.Clear();
            lastDecodeTime = DateTime.MinValue;
            isBarcodeScanned = false;

            // 停止当前运行的摄像头
            await StopCameraAsync();

            try
            {
                // 初始化选定的摄像头设备
                var device = new VideoCaptureDevice(videoDevices[cmbCamera.SelectedIndex].MonikerString);
                videoSource = device;

                // 登录事件处理程序
                videoSource.NewFrame += VideoSource_NewFrame;
                videoSource.VideoSourceError += VideoSource_VideoSourceError;

                // 开始视频捕获
                videoSource.Start();

                // 更新UI状态
                lblStatus.Text = "扫描中...";
                lblStatus.ForeColor = Color.Blue;
                btn_cam_stop.Enabled = true;
                btn_cam_start.Enabled = false;
                isStopping = false;
                //MessageBox.Show("摄像头启动成功，数据初始化成功！");
            }
            catch (Exception ex)
            {
                MessageBox.Show($"摄像头启动失败: {ex.Message}", "错误",
                                MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// 核实信息按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_Infor_Click(object sender, EventArgs e)
        {
            isCheck = false;
            string str = string.Empty;
            #region   校验当前用户信息

            if (string.IsNullOrWhiteSpace(_userguid) || string.IsNullOrWhiteSpace(_username))
            {
                //MessageBox.Show($"当前用户信息不准确，需重新登录，UserName：{_username},UserID：{_userguid},");
                //初始化提示信息
                button_ShowMess_Mes(AntdUI.TTypeMini.Error, "当前用户信息不准确，需重新登录");
                return;
            }

            #endregion

            #region 做非空校验 和 数据校验

              
            if (string.IsNullOrWhiteSpace(textBox_Tag.Text))
            {
                isCheck = false;

                //提示变色
                button_BackColor("textBox_Tag");
                //初始化提示信息
                button_ShowMess_Mes(AntdUI.TTypeMini.Error, "请重新确认衣物条形码输入是否正确");
                Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", "请重新确认衣物条形码输入是否正确，Text：" + textBox_Tag.Text);

                Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"清空数据，textBox_Tag:{textBox_Tag.Text},input_SensorID1:{input_SensorID1.Text},input_SensorID2:{input_SensorID2.Text}");

                //清空数据
                textBox_Tag.Text = "";
                input_SensorID1.Text = "";
                input_SensorID2.Text = "";
                return;
            }
            else if (string.IsNullOrWhiteSpace(input_SensorID1.Text))
            {
                isCheck = false;
                //提示变色
                button_BackColor("input_SensorID1");
                //初始化提示信息
                button_ShowMess_Mes(AntdUI.TTypeMini.Error, $"请重新确认传感器1输入是否正确，[{input_SensorID1.Text}]");
                Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", "请重新确认传感器1输入是否正确，Text：" + input_SensorID1.Text);
                Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"清空数据，input_SensorID1:{input_SensorID1.Text},input_SensorID2:{input_SensorID2.Text}");
                //清空数据
                textBox_Tag.Text = "";
                input_SensorID1.Text = "";
                input_SensorID2.Text = "";
                return;
            }
            else if (string.IsNullOrWhiteSpace(input_SensorID2.Text))
            {
                isCheck = false;

                //提示变色
                button_BackColor("input_SensorID2");
                //初始化提示信息
                button_ShowMess_Mes(AntdUI.TTypeMini.Error, $"请重新确认传感器2输入是否正确，[{input_SensorID2.Text}]");
                Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", "请重新确认传感器2输入是否正确，Text：" + input_SensorID2.Text);
                Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"清空数据，textBox_Tag:{textBox_Tag.Text},input_SensorID1:{input_SensorID1.Text},input_SensorID2:{input_SensorID2.Text}");
                //清空数据
                textBox_Tag.Text = "";
                input_SensorID1.Text = "";
                input_SensorID2.Text = "";
                return;
            }
            else
            {

                isCheck = false;
                //初始化提示信息
                button_ShowMess_Mes(AntdUI.TTypeMini.Default, "校验内容全部正确，请继续操作！");
                Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", "内容全部正确，请继续操作！");

                #region 创建 数据库连接，并刷新展示的数据

                // 获取全局SqlSugar实例
                var db = SqlSugarHelper.Db;

                // 执行查询
                List<Tb_Clothes> list = db.Queryable<Tb_Clothes>()
                  //.Where(s => s.CreatedDatetime > DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))
                  //.Where(s => SqlFunc.ToDate(s.CreatedDatetime) > DateTime.Now.AddDays(-2))
                  //.Where(s => s.CreatedUserID == _userguid)
                  .Where(s => s.CreatedUserName == _username)
                  .Take(1000)
                  .OrderByDescending(s => s.CreatedDatetime)
                  .ToList();

                // 显示到DataGridView
                dataGridView_table.DataSource = list;

                // 记录成功日志
                Log4.Info($"Log4/sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", "成功加载Tb_Clothes数据2");


                #endregion


                #region 做强校验，衣物条码是否已存在，且是否已结束流程
                //获取保存 当前衣物ID 和 传感器1，2的唯一主键
                string TagGuid = string.Empty;
                int count = 0;
                try
                {
                    #region     条件查询,判断当前数据是否已经存在于Tb_Clothes中，且校验当前状态是否允许继续操作
                    count = db.Queryable<Tb_Clothes>()
                        .Where(it => it.TagID == textBox_Tag.Text)
                        .Where(it => it.SensorID1 == input_SensorID1.Text)
                        .Where(it => it.SensorID2 == input_SensorID2.Text)
                        .Where(it => it.IsAuditing == "0")
                        .Count();

                    if (count > 0)
                    {
                        //提示变色
                        button_BackColor("textBox_Tag");
                        //初始化提示信息
                        button_ShowMess_Mes(AntdUI.TTypeMini.Error, $"吊牌数据已经存在，且流程未结束，不要重复扫描！【{textBox_Tag.Text}】");
                        Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"数据校验提示：吊牌数据已经存在，且流程未结束，不要重复扫描！ Tb_Clothes表数据已存在：" +
                            $"TagID={textBox_Tag.Text} ，SensorID1={input_SensorID1.Text} ，SensorID2={input_SensorID2.Text} ，IsAuditing={0} ");
                        return;
                    }
                    count = 0;
                    count = db.Queryable<Tb_Clothes>()
                        .Where(it => it.TagID == textBox_Tag.Text)
                        .Where(it => it.SensorID1 == input_SensorID1.Text)
                        .Where(it => it.SensorID2 == input_SensorID2.Text)
                        .Where(it => it.IsAuditing == "1")
                        .Count();
                    if (count > 0)
                    {
                        //提示变色
                        button_BackColor("textBox_Tag");
                        //初始化提示信息
                        button_ShowMess_Mes(AntdUI.TTypeMini.Error, $"吊牌数据已经存在，且流程已结束，不要重复扫描！【{textBox_Tag.Text}】");
                        Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"数据校验提示：吊牌数据已经存在，且流程已结束，Tb_Clothes表数据已存在：" +
                           $"TagID={textBox_Tag.Text} ，SensorID1={input_SensorID1.Text} ，SensorID2={input_SensorID2.Text} ，IsAuditing={1} ");
                        return;
                    }
                    count = 0;
                    count = db.Queryable<Tb_Clothes>()
                       .Where(it => it.TagID == textBox_Tag.Text)
                       .Where(it => it.IsAuditing == "0")
                       .Count();
                    if (count > 0)
                    {
                        //提示变色
                        button_BackColor("textBox_Tag");
                        //初始化提示信息
                        button_ShowMess_Mes(AntdUI.TTypeMini.Error, $"吊牌数据已经存在，且流程未结束，不要重复扫描！【{textBox_Tag.Text}】");
                        Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"数据校验提示：吊牌数据已经存在，且流程未结束，不要重复扫描！ Tb_Clothes表数据已存在：" +
                            $"TagID={textBox_Tag.Text} ，SensorID1={input_SensorID1.Text} ，SensorID2={input_SensorID2.Text} ，IsAuditing={0} ");
                        return;
                    }
                    /*  
                     *  因后期吊牌可能会重复使用，所以去掉此校验
                     *  count = db.Queryable<Tb_Clothes>()
                        .Where(it => it.TagID == textBox_Tag.Text)
                        .Where(it => it.IsAuditing == "1")
                        .Count();
                      if (count > 0)
                      {
                           //提示变色
                           button_BackColor("textBox_Tag");
                          //初始化提示信息
                          button_ShowMess_Mes(AntdUI.TTypeMini.Error, $"吊牌数据已经存在，且流程已结束，不要重复扫描！【{textBox_Tag.Text}】");
                          Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"数据校验提示：Tb_Clothes表数据已存在：" +
                             $"TagID={textBox_Tag.Text} ，SensorID1={input_SensorID1.Text} ，SensorID2={input_SensorID2.Text} ，IsAuditing={1} ");
                          return;
                      }*/
                    #endregion 条件查询,判断当前数据是否已经存在于Tb_Clothes中，且校验当前状态是否允许继续操作

                    #region 条件查询,判断当前数据在Tb_Sensor 中的使用状态

                    count = 0;
                    count = db.Queryable<Tb_Sensor>()
                        .Where(it => it.TagID == textBox_Tag.Text)
                        .Where(it => it.SensorID == input_SensorID1.Text)
                        .Where(it => it.State == 1)
                        .Count();
                    if (count > 0)
                    {
                        isCheck = false;
                        //提示变色
                        button_BackColor("input_SensorID1");
                        //初始化提示信息
                        button_ShowMess_Mes(AntdUI.TTypeMini.Error, $"当前传感器传感器1[{input_SensorID1.Text}]正在使用,不要重复使用！");
                        Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"数据校验提示：当前传感器SensorID：{input_SensorID1.Text}，正在使用中State={1}，不能重复绑定! ");
                        return;
                    }

                    count = 0;
                    count = db.Queryable<Tb_Sensor>()
                        .Where(it => it.TagID == textBox_Tag.Text)
                        .Where(it => it.SensorID == input_SensorID2.Text)
                        .Where(it => it.State == 1)
                        .Count();
                    if (count > 0)
                    {
                        isCheck = false;
                        //提示变色
                        button_BackColor("input_SensorID2");
                        //初始化提示信息
                        button_ShowMess_Mes(AntdUI.TTypeMini.Error, $"当前传感器传感器2[{input_SensorID2.Text}]正在使用,不要重复使用！");
                        Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"数据校验提示：当前传感器SensorID：{input_SensorID2.Text}，正在使用中State={1}，不能重复绑定! ");

                        return;
                    }
                    count = 0;
                    count = db.Queryable<Tb_Sensor>()
                        .Where(it => it.SensorID == input_SensorID1.Text)
                        .Where(it => it.State == 1)
                        .Count();
                    if (count > 0)
                    {
                        isCheck = false;
                        //提示变色
                        button_BackColor("input_SensorID1");
                        //初始化提示信息
                        button_ShowMess_Mes(AntdUI.TTypeMini.Error, $"当前传感器传感器1[{input_SensorID1.Text}]正在使用,不要重复使用！");
                        Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"数据校验提示：当前传感器SensorID：{input_SensorID1.Text}，正在使用中State={1}，不能重复绑定! ");
                        return;
                    }

                    count = 0;
                    count = db.Queryable<Tb_Sensor>()
                        .Where(it => it.SensorID == input_SensorID2.Text)
                        .Where(it => it.State == 1)
                        .Count();
                    if (count > 0)
                    {
                        isCheck = false;
                        //提示变色
                        button_BackColor("input_SensorID2");
                        //初始化提示信息
                        button_ShowMess_Mes(AntdUI.TTypeMini.Error, $"当前传感器传感器2[{input_SensorID2.Text}]正在使用,不要重复使用！");
                        Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"数据校验提示：当前传感器SensorID：{input_SensorID2.Text}，正在使用中State={1}，不能重复绑定! ");

                        return;
                    }
                    //初始化提示信息
                    button_ShowMess_Mes(AntdUI.TTypeMini.Default, "校验通过，等待保存！");
                    isCheck = true;
                    #endregion

                }
                catch (Exception ex)
                {
                    //初始化提示信息
                    button_ShowMess_Mes(AntdUI.TTypeMini.Error, $"校验未通过，{ex.Message}");
                    // 详细异常日志/错误日志
                    Log4.Error("System/Exceptions",
                        $"数据衣物条码强校验失败: {ex.Message} , 异常详情: {ex} ");
                    Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"数据衣物条码强校验失败: {ex.Message} , 异常详情: {ex} ");
                    return;
                }

                #endregion




            }


            #endregion
        }

        /// <summary>
        /// 信息校验—核实信息按钮-扫码直接调用
        /// </summary>
        private void btn_Infor_Click_Save()
        {

            isCheck = false;


            #region 做非空校验 和 数据校验

            if (string.IsNullOrWhiteSpace(textBox_Tag.Text))
            {
                isCheck = false;
                //提示变色
                button_BackColor("textBox_Tag");
                //初始化提示信息
                button_ShowMess_Mes(AntdUI.TTypeMini.Error, $"请重新确认衣物条形码输入是否正确![{textBox_Tag.Text}]");
                Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", "请重新确认衣物条形码输入是否正确，Text：" + textBox_Tag.Text);
                Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"清空数据，textBox_Tag:{textBox_Tag.Text},input_SensorID1:{input_SensorID1.Text},input_SensorID2:{input_SensorID2.Text}");
                //清空数据
                textBox_Tag.Text = "";
                input_SensorID1.Text = "";
                input_SensorID2.Text = "";
                return;
            }
            else if (string.IsNullOrWhiteSpace(input_SensorID1.Text))
            {
                isCheck = false;
                //提示变色
                button_BackColor("input_SensorID1");
                //初始化提示信息
                button_ShowMess_Mes(AntdUI.TTypeMini.Error, $"请重新确认传感器1输入是否正确![{input_SensorID1.Text}]");

                Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", "请重新确认传感器1输入是否正确，Text：" + input_SensorID1.Text);
                Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"清空数据，input_SensorID1:{input_SensorID1.Text},input_SensorID2:{input_SensorID2.Text}");
                //清空数据
                textBox_Tag.Text = "";
                input_SensorID1.Text = "";
                input_SensorID2.Text = "";
                return;
            }
            else if (string.IsNullOrWhiteSpace(input_SensorID2.Text))
            {
                isCheck = false;
                //提示变色
                button_BackColor("input_SensorID2");
                //初始化提示信息
                button_ShowMess_Mes(AntdUI.TTypeMini.Error, $"请重新确认传感器2输入是否正确![{input_SensorID2}]");
                Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", "请重新确认传感器2输入是否正确，Text：" + input_SensorID2.Text);
                Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"清空数据，textBox_Tag:{textBox_Tag.Text},input_SensorID1:{input_SensorID1.Text},input_SensorID2:{input_SensorID2.Text}");
                //清空数据
                textBox_Tag.Text = "";
                input_SensorID1.Text = "";
                input_SensorID2.Text = "";
                return;
            }
            else
            {

                isCheck = false;
                //MessageBox.Show("校验内容全部正确，请继续操作！");
                //初始化提示信息
                button_ShowMess_Mes(AntdUI.TTypeMini.Default, "校验内容全部正确，请继续操作！");
                Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", "内容全部正确，请继续操作！");

                #region 创建 数据库连接，并刷新展示的数据

                // 获取全局SqlSugar实例
                var db = SqlSugarHelper.Db;

                // 执行查询
                List<Tb_Clothes> list = db.Queryable<Tb_Clothes>()
                  //.Where(s => s.CreatedDatetime > DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))
                  //.Where(s => SqlFunc.ToDate(s.CreatedDatetime) > DateTime.Now.AddDays(-2))
                  //.Where(s => s.CreatedUserID == _userguid)
                  .Where(s => s.CreatedUserName == LoginUserName) //_username ??label_name.Text
                  .Take(1000)
                  .OrderByDescending(s => s.CreatedDatetime)
                  .ToList();

                // 显示到DataGridView
                dataGridView_table.DataSource = list;

                // 记录成功日志
                Log4.Info($"Log4/sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", "成功加载Tb_Clothes数据2");


                #endregion


                #region 做强校验，衣物条码是否已存在，且是否已结束流程
                //获取保存 当前衣物ID 和 传感器1，2的唯一主键
                string TagGuid = string.Empty;
                int count = 0;
                try
                {
                    #region     条件查询,判断当前数据是否已经存在于Tb_Clothes中，且校验当前状态是否允许继续操作
                    count = db.Queryable<Tb_Clothes>()
                        .Where(it => it.TagID == textBox_Tag.Text)
                        .Where(it => it.SensorID1 == input_SensorID1.Text)
                        .Where(it => it.SensorID2 == input_SensorID2.Text)
                        .Where(it => it.IsAuditing == "0")
                        .Count();

                    if (count > 0)
                    {
                        //提示变色
                        button_BackColor("textBox_Tag");
                        //初始化提示信息
                        button_ShowMess_Mes(AntdUI.TTypeMini.Error, $"吊牌数据已经存在，但流程未结束，不能重复操作!【{textBox_Tag.Text}】");
                        Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"数据校验提示：吊牌数据已经存在，但流程未结束，不能重复操作! Tb_Clothes表数据已存在：" +
                            $"TagID={textBox_Tag.Text} ，SensorID1={input_SensorID1.Text} ，SensorID2={input_SensorID2.Text} ，IsAuditing={0} ");
                        return;
                    }
                    count = 0;
                    count = db.Queryable<Tb_Clothes>()
                        .Where(it => it.TagID == textBox_Tag.Text)
                        .Where(it => it.SensorID1 == input_SensorID1.Text)
                        .Where(it => it.SensorID2 == input_SensorID2.Text)
                        .Where(it => it.IsAuditing == "1")
                        .Count();
                    if (count > 0)
                    {
                        //提示变色
                        button_BackColor("textBox_Tag");
                        //初始化提示信息
                        button_ShowMess_Mes(AntdUI.TTypeMini.Error, $"吊牌数据已经存在，且流程已经结束，不能重复操作!【{textBox_Tag.Text}】");
                        Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"数据校验提示：吊牌数据已经存在，且流程已经结束，不能重复操作! Tb_Clothes表数据已存在：" +
                           $"TagID={textBox_Tag.Text} ，SensorID1={input_SensorID1.Text} ，SensorID2={input_SensorID2.Text} ，IsAuditing={1} ");
                        return;
                    }
                    count = 0;
                    count = db.Queryable<Tb_Clothes>()
                       .Where(it => it.TagID == textBox_Tag.Text)
                       .Where(it => it.IsAuditing == "0")
                       .Count();
                    if (count > 0)
                    {
                        //提示变色
                        button_BackColor("textBox_Tag");
                        //初始化提示信息
                        button_ShowMess_Mes(AntdUI.TTypeMini.Error, $"吊牌数据已经存在，但流程未结束，不能重复操作!【{textBox_Tag.Text}】");
                        Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"数据校验提示：吊牌数据已经存在，但流程未结束，不能重复操作! Tb_Clothes表数据已存在：" +
                            $"TagID={textBox_Tag.Text} ，SensorID1={input_SensorID1.Text} ，SensorID2={input_SensorID2.Text} ，IsAuditing={0} ");
                        return;
                    }
                    /*  
                     *  因后期吊牌可能会重复使用，所以去掉此校验
                     *  count = db.Queryable<Tb_Clothes>()
                        .Where(it => it.TagID == textBox_Tag.Text)
                        .Where(it => it.IsAuditing == "1")
                        .Count();
                      if (count > 0)
                      {
                            //提示变色
                           button_BackColor("textBox_Tag");
                          //初始化提示信息
                          button_ShowMess_Mes(AntdUI.TTypeMini.Error, $"吊牌数据已经存在，且流程已结束，不要重复扫描！【{textBox_Tag.Text}】");
                          Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"数据校验提示：Tb_Clothes表数据已存在：" +
                             $"TagID={textBox_Tag.Text} ，SensorID1={input_SensorID1.Text} ，SensorID2={input_SensorID2.Text} ，IsAuditing={1} ");
                          return;
                      }*/
                    #endregion 条件查询,判断当前数据是否已经存在于Tb_Clothes中，且校验当前状态是否允许继续操作

                    #region 条件查询,判断当前数据在Tb_Sensor 中的使用状态

                    count = 0;
                    count = db.Queryable<Tb_Sensor>()
                        .Where(it => it.TagID == textBox_Tag.Text)
                        .Where(it => it.SensorID == input_SensorID1.Text)
                        .Where(it => it.State == 1)
                        .Count();
                    if (count > 0)
                    {
                        isCheck = false;
                        //提示变色
                        button_BackColor("input_SensorID1");
                        //初始化提示信息
                        button_ShowMess_Mes(AntdUI.TTypeMini.Error, $"当前传感器传感器1[{input_SensorID1.Text}]正在使用,不要重复使用！");
                        Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"数据校验提示：当前传感器SensorID：{input_SensorID1.Text}，正在使用中State={1}，不能重复绑定! ");
                        return;
                    }

                    count = 0;
                    count = db.Queryable<Tb_Sensor>()
                        .Where(it => it.TagID == textBox_Tag.Text)
                        .Where(it => it.SensorID == input_SensorID2.Text)
                        .Where(it => it.State == 1)
                        .Count();
                    if (count > 0)
                    {
                        isCheck = false;
                        //提示变色
                        button_BackColor("input_SensorID2");
                        //初始化提示信息
                        button_ShowMess_Mes(AntdUI.TTypeMini.Error, $"当前传感器传感器2[{input_SensorID2.Text}]正在使用,不要重复使用！");
                        Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"数据校验提示：当前传感器SensorID：{input_SensorID2.Text}，正在使用中State={1}，不能重复绑定! ");

                        return;
                    }
                    count = 0;
                    count = db.Queryable<Tb_Sensor>()
                        .Where(it => it.SensorID == input_SensorID1.Text)
                        .Where(it => it.State == 1)
                        .Count();
                    if (count > 0)
                    {
                        isCheck = false;
                        //提示变色
                        button_BackColor("input_SensorID1");
                        //初始化提示信息
                        button_ShowMess_Mes(AntdUI.TTypeMini.Error, $"当前传感器传感器1[{input_SensorID1.Text}]正在使用,不要重复使用！");
                        Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"数据校验提示：当前传感器SensorID：{input_SensorID1.Text}，正在使用中State={1}，不能重复绑定! ");
                        return;
                    }

                    count = 0;
                    count = db.Queryable<Tb_Sensor>()
                        .Where(it => it.SensorID == input_SensorID2.Text)
                        .Where(it => it.State == 1)
                        .Count();
                    if (count > 0)
                    {
                        isCheck = false;
                        //提示变色
                        button_BackColor("input_SensorID2");
                        //初始化提示信息
                        button_ShowMess_Mes(AntdUI.TTypeMini.Error, $"当前传感器传感器2[{input_SensorID2.Text}]正在使用,不要重复使用！");
                        Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"数据校验提示：当前传感器SensorID：{input_SensorID2.Text}，正在使用中State={1}，不能重复绑定! ");

                        return;
                    }
                    //初始化提示信息
                    button_ShowMess_Mes(AntdUI.TTypeMini.Default, "校验通过，等待保存！");
                    isCheck = true;
                    #endregion

                }
                catch (Exception ex)
                {
                   
                    //初始化提示信息
                    button_ShowMess_Mes(AntdUI.TTypeMini.Error, $"校验未通过，{ex.Message}");
                    // 详细异常日志/错误日志
                    Log4.Error("System/Exceptions",
                        $"数据衣物条码强校验失败: {ex.Message} , 异常详情: {ex} ");
                    Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"数据衣物条码强校验失败: {ex.Message} , 异常详情: {ex} ");
                    throw;
                }

                #endregion




            }


            #endregion
        }

        /// <summary>
        /// 提交确认提交/保存按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_save_Click(object sender, EventArgs e)
        {
            
            #region   校验当前用户信息

            if (string.IsNullOrWhiteSpace(_userguid) || string.IsNullOrWhiteSpace(_username))
            {
                //初始化提示信息
                button_ShowMess_Mes(AntdUI.TTypeMini.Error, "当前用户信息不准确，需重新登录！");
                return;
            }

            #endregion
            if (isCheck == false)
            {
                try
                {
                    //自动调用校验
                    btn_Infor_Click_Save();
                    
                }
                catch (Exception)
                {
                     
                    return;
                }
                
                /*//初始化提示信息
                button_ShowMess_Mes(AntdUI.TTypeMini.Error, "校验未通过，请重新扫描吊牌二维码进行校验!");*/
                Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"校验未通过，请重新扫描吊牌二维码进行校验!" +
                     $"TagID={textBox_Tag.Text},SensorID1 == {input_SensorID1.Text} ,SensorID2 == {input_SensorID2.Text}");
                return;
            }
            else
            {
                #region 提交数据
                try
                {


                    //插入一条新数据到Tb_Clothes中
                    In_Tb_Clothes();

                    //更新数据到 Tb_Sensor
                    InorUp_Tb_Sensor();


                    var form = new MessageForms("成功：", $"所有数据提交成功，等待下一次数据扫描！", true);
                    form.ShowDialog();
                    //初始化提示信息
                    button_ShowMess_Mes(AntdUI.TTypeMini.Success, "所有数据提交成功，等待下一次数据扫描！");
                    SimpleSpeaker.Say("成功！");
                }
                catch (Exception ex)
                {
                    //提示变色
                    button_BackColor("textBox_Tag");
                    //提示变色
                    button_BackColor("input_SensorID1");
                    //提示变色
                    button_BackColor("input_SensorID2");
                    
                    //初始化提示信息
                    button_ShowMess_Mes(AntdUI.TTypeMini.Error, $"保存提交数据时报错: {ex.Message} , 异常详情: {ex} ");
                    // 详细异常日志/错误日志
                    Log4.Error("System/Exceptions",
                        $"保存提交数据时报错: {ex.Message} , 异常详情: {ex} ");
                    Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"保存提交数据时报错: {ex.Message} , 异常详情: {ex} ");
                    throw;
                }
                finally
                {
                    #region 清空已处理的数据
                    textBox_Tag.Clear();
                    input_SensorID1.Clear();
                    input_SensorID2.Clear();
                    #endregion
                    // 无论成功与否，恢复校验状态
                    isCheck = false;
                }
                #endregion

                //初始化提示信息
                button_ShowMess_Mes(AntdUI.TTypeMini.Default, $"数据保存成功，等待下一次数据扫描！！");
            }



            #region 重新加载dataGridView_table数据

            // 获取全局SqlSugar实例
            var db = SqlSugarHelper.Db;

            // 执行查询
            List<Tb_Clothes> list = db.Queryable<Tb_Clothes>()
              //.Where(s => s.CreatedDatetime > DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))
              //.Where(s => SqlFunc.ToDate(s.CreatedDatetime) > DateTime.Now.AddDays(-2))
              //.Where(s => s.CreatedUserID == _userguid)
              .Where(s => s.CreatedUserName == _username)
              .Take(1000)
              .OrderByDescending(s => s.CreatedDatetime)
              .ToList();

            // 显示到DataGridView
            dataGridView_table.DataSource = list;

            // 记录成功日志
            Log4.Info($"Log4/sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", "并成功加载Tb_Clothes数据");

            #endregion  重新加载dataGridView_table数据

        }

        /// <summary>
        /// 提交确认提交/保存按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_save_Click()
        {
            #region   校验当前用户信息
            if (string.IsNullOrWhiteSpace(_userguid) || string.IsNullOrWhiteSpace(_username))
            {
                //MessageBox.Show($"当前用户信息不准确，需重新登录，UserName：{_username},UserID：{_userguid},");
                //初始化提示信息
                button_ShowMess_Mes(AntdUI.TTypeMini.Error, "当前用户信息不准确，需重新登录！");
                return;
            }

            #endregion
            if (isCheck == false)
            {
                try
                {
                    //自动调用校验
                    btn_Infor_Click_Save();
                    
                }
                catch (Exception)
                {

                    return;
                }

              /*  //初始化提示信息
                button_ShowMess_Mes(AntdUI.TTypeMini.Error, "校验未通过，请重新扫描吊牌二维码进行校验!");*/
                Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"校验未通过，请重新扫描吊牌二维码进行校验!" +
                     $"TagID={textBox_Tag.Text},SensorID1 == {input_SensorID1.Text} ,SensorID2 == {input_SensorID2.Text}");
                return;
            }
            else
            {
                #region 提交数据
                try
                {


                    //插入一条新数据到Tb_Clothes中
                    In_Tb_Clothes();

                    //更新数据到 Tb_Sensor
                    InorUp_Tb_Sensor();

                    var form = new MessageForms("成功：", $"所有数据提交成功，等待下一次数据扫描！", true);
                    form.ShowDialog();
                    //初始化提示信息
                    button_ShowMess_Mes(AntdUI.TTypeMini.Success, "所有数据提交成功，等待下一次数据扫描！");
                    SimpleSpeaker.Say("成功！");
                }
                catch (Exception ex)
                {
                    //提示变色
                    button_BackColor("textBox_Tag");
                    //提示变色
                    button_BackColor("input_SensorID1");
                    //提示变色
                    button_BackColor("input_SensorID2");

                    //初始化提示信息
                    button_ShowMess_Mes(AntdUI.TTypeMini.Error, $"保存提交数据时报错: {ex.Message} , 异常详情: {ex} ");
                    // 详细异常日志/错误日志
                    Log4.Error("System/Exceptions",
                        $"保存提交数据时报错: {ex.Message} , 异常详情: {ex} ");
                    Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"保存提交数据时报错: {ex.Message} , 异常详情: {ex} ");
                    throw;
                }
                finally
                {
                    #region 清空已处理的数据
                    textBox_Tag.Clear();
                    input_SensorID1.Clear();
                    input_SensorID2.Clear();
                    #endregion
                    // 无论成功与否，恢复校验状态
                    isCheck = false;
                }
                #endregion


            }

            #region 重新加载dataGridView_table数据

            // 获取全局SqlSugar实例
            var db = SqlSugarHelper.Db;

            // 执行查询
            List<Tb_Clothes> list = db.Queryable<Tb_Clothes>()
              //.Where(s => s.CreatedDatetime > DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))
              //.Where(s => SqlFunc.ToDate(s.CreatedDatetime) > DateTime.Now.AddDays(-2))
              //.Where(s => s.CreatedUserID == _userguid)
              .Where(s => s.CreatedUserName == _username)
              .Take(1000)
              .OrderByDescending(s => s.CreatedDatetime)
              .ToList();

            // 显示到DataGridView
            dataGridView_table.DataSource = list;

            // 记录成功日志
            Log4.Info($"Log4/sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", "并成功加载Tb_Clothes数据");


            #endregion  重新加载dataGridView_table数据
            
            //初始化提示信息
            button_ShowMess_Mes(AntdUI.TTypeMini.Default, $"自动执行数据保存成功，等待下一次数据扫描！！");
        }



        /// <summary>
        /// 当条码输入框按下回车键时触发
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void textBox_Tag_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (!string.IsNullOrWhiteSpace(textBox_Tag.Text))
            {
                // 检查按下的键是否是回车键（Enter键的KeyChar是13或'\r'）
                if (e.KeyChar == (char)13 || e.KeyChar == '\r')
                {
                    /*// 阻止系统发出"嘀"声
                    e.Handled = true;*/

                    // 调用指定方法
                    OnBarcodeScanned(textBox_Tag.Text);
                }
            }
            else
            {
                //变色
                button_BackColor("textBox_Tag");
                //初始化信息
                button_ShowMess_Mes(AntdUI.TTypeMini.Error, "吊牌条码为空，请重新输入！");
                
            }
            //
            //button_ShowMess_Mes(AntdUI.TTypeMini.Error,"吊牌条码自动执行未通过，请重新检查信息是否正确！");

        }

        #region  图像
        /// <summary>
        /// 吊牌条码识别成功后的处理，自动调用保存和提交按钮
        /// </summary>
        /// <param name="barcode"></param>
        private void OnBarcodeScanned(string barcode)
        {
            // 输出条码
            //MessageBox.Show($"条码识别成功后的处理，条码: {barcode}");

            // 识别成功后更新状态/重置扫描状态
            isBarcodeScanned = false;
            //txtBarcode.Clear();
            // 更新UI状态
            lblStatus.Text = "扫描中...";
            lblStatus.ForeColor = Color.Blue;
            btn_cam_start.Enabled = false;
            btn_cam_stop.Enabled = true;
            isStopping = false;

            // 实际应用中可添加：
            try
            {
                var config = AppConfig.LoadConfig();
                if (config.AllConfig.IsAutoInfor_Click ==1 )
                {
                    try
                    {
                        //自动调用校验
                        btn_Infor_Click_Save();
                    }
                    catch (Exception)
                    {
                        //初始化提示信息
                        button_ShowMess_Mes(AntdUI.TTypeMini.Error, "自动调用数据校验失败，若多次报错，请尽快联系管理员！");
                        return;
                    }
                }
                if (config.AllConfig.IsAutobtn_save == 1)
                {
                    try
                    {
                        //自动调用提交/保存
                        btn_save_Click();
                        ////初始化提示信息
                    }
                    catch (Exception)
                    {
                        //初始化提示信息
                        button_ShowMess_Mes(AntdUI.TTypeMini.Error, "自动调用提交/保存失败，若多次报错，请尽快联系管理员！");
                        return;
                    }
                }
            }
            catch (Exception)
            {
                //初始化提示信息
                button_ShowMess_Mes(AntdUI.TTypeMini.Error, "自动执行提交数据报错，若多次报错，请尽快联系管理员！");
                return;
            }

            // 2. 库存更新
            // 3. 显示商品信息
        }

        /// <summary>
        /// 性能模式
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void chkPerformanceMode_CheckedChanged(object sender, EventArgs e)
        {

            /*// 1. 根据模式设置帧率和识别参数（确保MAX_FPS生效）
            if (chkPerformanceMode.Checked)
            {
                // 性能模式：降低帧率
                MAX_FPS_ch = 20; // 直接修改变量
                barcodeReader.Options.TryHarder = false;
            }
            else
            {
                // 质量模式：提高帧率
                MAX_FPS_ch = 30; // 直接修改变量
                barcodeReader.Options.TryHarder = true;
            }*/
            // 1. 根据模式设置帧率和识别参数（确保MAX_FPS生效）
            if (chkPerformanceMode.Checked)
            {
                // 性能模式：降低帧率
                VideoMaxOrMinFPS = VideoMinFPS;  
                barcodeReader.Options.TryHarder = false;
            }
            else
            {
                // 质量模式：提高帧率
                VideoMaxOrMinFPS = VideoMaxFPS;  
                barcodeReader.Options.TryHarder = true;
            }

            // 2. 检查摄像头状态及设备可用性，避免启动失败
            if (videoSource == null || !videoSource.IsRunning)
            {
                #region  图像

                // 检测所有可用的视频输入设备
                videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);

                // 如果没有检测到摄像头设备
                if (videoDevices.Count == 0)
                {
                    MessageBox.Show("未检测到可用摄像头。请连接摄像头后重启应用。",
                                    "设备错误",
                                    MessageBoxButtons.OK,
                                    MessageBoxIcon.Error);
                    btn_cam_stop.Enabled = false; // 禁用开始按钮
                    return;
                }
                btn_cam_stop.Enabled = true; // 放开开始按钮
                // 将检测到的摄像头添加到下拉列表
                foreach (FilterInfo device in videoDevices)
                {
                    cmbCamera.Items.Add(device.Name);
                }

                // 默认选择第一个摄像头
                cmbCamera.SelectedIndex = 0;

                // 初始化状态标签
                lblStatus.Text = "就绪";
                lblStatus.ForeColor = Color.Green;

                #endregion 图像

                // 关键修复1：先检查设备是否已枚举（避免无设备时启动）
                if (videoDevices == null || videoDevices.Count == 0)
                {
                    // 重新枚举设备（防止设备未加载）
                    videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
                    if (videoDevices.Count == 0)
                    {
                        MessageBox.Show("未检测到摄像头设备，请检查硬件连接", "启动失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return; // 无设备，直接返回
                    }
                }
                Thread.Sleep(1000);
                // 关键修复2：确保启动按钮可点击，并添加异常捕获

                try
                {
                    // 关键修复3：先实例化videoSource（防止null引用）
                    if (videoSource == null)
                    {
                        videoSource = new VideoCaptureDevice(videoDevices[0].MonikerString); // 使用第一个设备
                        videoSource.NewFrame += VideoSource_NewFrame; // 绑定帧事件（如果之前未绑定）
                    }

                    // 触发启动，并捕获按钮点击中的异常
                    btn_cam_start.PerformClick();

                    // 验证是否真的启动成功
                    if (!videoSource.IsRunning)
                    {
                        throw new Exception("按钮点击后摄像头仍未启动，请检查启动逻辑");
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"启动摄像头失败：{ex.Message}", "启动错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    Log4.Error("Camera/StartFail", $"未运行状态下启动失败：{ex}");
                }
                return;
            }

            // 3. 摄像头正在运行：先等待停止完成，再启动（关键修复）
            try
            {
                // 等待停止完成（使用await确保异步操作结束）
                await StopCameraAsync();

                // 停止后延迟500ms（给设备释放时间，比1秒更合理）
                await Task.Delay(500);
                btn_cam_start.Enabled = true;
                // 仅启动一次（去掉重复调用）
                btn_cam_start.PerformClick();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"模式切换失败：{ex.Message}", "摄像头错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Log4.Error("Camera/ModeChange", $"切换性能模式异常：{ex}");
            }
        }
        

        /// <summary>
        /// 主窗体关闭事件（修复关闭不掉问题：彻底释放子窗体+摄像头资源）
        /// </summary>
        private async void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            // 1. 先彻底关闭HFReader子窗体（关键：不隐藏，直接关闭）
            if (hFReaderInstance != null && !hFReaderInstance.IsDisposed)
            {
                // 取消子窗体的FormClosing事件中“隐藏逻辑”，强制关闭
                hFReaderInstance.FormClosing -= (s, args) => { }; // 解绑原有冲突事件
                hFReaderInstance.FormClosing += (s, args) =>
                {
                    args.Cancel = false; // 允许子窗体关闭，不取消（保留原逻辑）
                    var form2 = s as HFReader; // 保留原逻辑
                                               // 仅把“form2?.DataUpdated”改成“if非空判断”（正式版语法，无报错）
                    if (form2 != null)
                    {
                        form2.DataUpdated -= OnForm2DataUpdated; // 解绑数据事件
                    }
                };
                hFReaderInstance.Dispose(); // 彻底释放子窗体资源
                hFReaderInstance.Close(); // 强制关闭子窗体

                hFReaderInstance = null;
                Log4.Info("System/CloseOut", "HFReader子窗体已彻底关闭");
            }

            // 2. 安全取消所有异步操作
            if (formClosingCts != null && !formClosingCts.IsCancellationRequested)
            {
                formClosingCts.Cancel();
            }

            // 3. 等待摄像头异步停止完成（关键：避免线程占用）
            if (videoSource != null && videoSource.IsRunning)
            {
                e.Cancel = true; // 先阻止当前关闭，等待摄像头停止
                lblStatus.Text = "正在关闭摄像头...";
                lblStatus.ForeColor = Color.Orange;

                // 等待摄像头停止（异步等待，确保资源释放）
                await StopCameraAsync();

                // 释放摄像头资源
                // 解绑摄像头事件
                if (videoSource != null)
                {
                    videoSource.NewFrame -= VideoSource_NewFrame;
                    videoSource.VideoSourceError -= VideoSource_VideoSourceError;
                }
                /* videoSource.NewFrame -= VideoSource_NewFrame;
                videoSource.VideoSourceError -= VideoSource_VideoSourceError;*/
                videoSource = null;
                ReleaseResources(); // 释放图像资源
                Log4.Info("System/CloseOut", "摄像头资源已彻底释放");

                // 重新触发关闭（此时资源已释放）
                this.FormClosing -= Form1_FormClosing; // 解绑当前事件，避免递归
                this.Close();
                Log4.Info("System/CloseOut", "已退出");
            }
            else
            {
                // 无摄像头资源占用，直接释放其他资源
                ReleaseResources();
                e.Cancel = false; // 允许主窗体关闭
            }
        }

        /// <summary>
        /// 替换 VideoSource_NewFrame 方法内处理帧的逻辑，采用异步方式处理条码识别，避免阻塞 UI 线程和摄像头画面刷新
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="eventArgs"></param>

        private void VideoSource_NewFrame(object sender, NewFrameEventArgs eventArgs)
        {
            // 检查窗体是否正在关闭
            if (formClosingCts?.IsCancellationRequested == true) return;

            // 帧率控制：如果帧率过高则跳过
            var now = DateTime.Now;
            if ((now - lastFrameTime).TotalMilliseconds < (1000.0 / VideoMaxOrMinFPS))
            {
                eventArgs.Frame.Dispose();
                return;
            }
            lastFrameTime = now;

            Bitmap frame = null;
            try
            {
                // 克隆帧以避免资源冲突
                frame = (Bitmap)eventArgs.Frame.Clone();
                Bitmap centered = CreateCenteredImage(frame, pbCamera.Size);

                // 更新UI显示
                if (pbCamera.InvokeRequired)
                {
                    pbCamera.BeginInvoke(new Action<Bitmap>(UpdateCameraDisplay), centered);
                }
                else
                {
                    UpdateCameraDisplay(centered);
                }

                // 异步处理帧，避免阻塞主线程
                if (!isProcessingFrame)
                {
                    isProcessingFrame = true;
                    // 释放上一次处理帧
                    if (lastProcessedFrame != null)
                    {
                        lastProcessedFrame.Dispose();
                    }
                    lastProcessedFrame = (Bitmap)frame.Clone();

                    // 使用线程池异步处理条码识别
                    ThreadPool.QueueUserWorkItem(_ =>
                    {
                        try
                        {
                            ProcessFrameForBarcode(lastProcessedFrame);
                        }
                        finally
                        {
                            isProcessingFrame = false;
                        }
                    });
                }
            }
            catch (Exception ex)
            {
                Console.Write($"处理帧时出错: {ex.Message}");

            }
            finally
            {
                frame?.Dispose();
            }
        }

        /// <summary>
        /// 更新摄像头显示（整合修复：释放逻辑异常+Bitmap.IsDisposed报错）
        /// </summary>
        /// <param name="frame">传入的摄像头帧</param>
        private void UpdateCameraDisplay(Bitmap frame)
        {
            // 1. 基础校验：控件/窗体已释放或帧无效时，直接安全退出
            if (pbCamera.IsDisposed || this.IsDisposed || frame == null)
            {
                frame?.Dispose(); // 避免传入帧内存泄漏
                return;
            }

            // 2. 线程安全锁：确保同一时间只有一个线程操作摄像头图像（防止资源冲突）
            lock (_cameraImageLock)
            {
                Bitmap newFrame = null; // 克隆后的独立帧（与后台线程资源隔离）
                try
                {
                    // 3. 克隆新帧：UI线程用独立资源，不与后台线程共用原帧（避免“对象正在使用”异常）
                    newFrame = (Bitmap)frame.Clone();

                    // 4. 安全获取旧图像：用 as 转换替代强转（修复“强转异常”问题）
                    var oldBitmap = pbCamera.Image as Bitmap;

                    // 5. 先赋值新图像，再释放旧图像（确保控件不再渲染旧图）
                    pbCamera.Image = newFrame;

                    // 6. 释放旧图像：去掉 IsDisposed 检查（修复“Bitmap未包含IsDisposed”报错，Dispose幂等无需判断）
                    if (oldBitmap != null)
                    {
                        // 额外保障：先解绑控件引用，再释放（彻底避免渲染冲突）
                        if (pbCamera.Image == oldBitmap)
                        {
                            pbCamera.Image = null;
                        }
                        oldBitmap.Dispose();
                    }
                }
                catch (Exception ex)
                {
                    // 异常兜底：释放新帧避免内存泄漏，同时提示用户
                    newFrame?.Dispose();
                    //MessageBox.Show($"摄像头显示更新失败：{ex.Message}", "图像错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    Log4.Error("Camera/DisplayError", $"异常详情：{ex}");
                }
                finally
                {
                    // 7. 释放原帧：去掉 frame != newFrame 多余判断（克隆后必然不等，判断无意义）
                    // 同时去掉 IsDisposed 检查（修复报错，Dispose幂等安全）
                    frame?.Dispose();
                }
            }
        }

        /// <summary>
        /// 处理帧进行条码识别（在后台线程）识别频率限制,最小识别间隔：
        /// </summary>
        /// <param name="frame"></param>
        private void ProcessFrameForBarcode(Bitmap frame)
        {
            // 标记为正在处理
            isProcessingFrame = true;

            try
            {
                // 检查是否满足识别间隔要求
                var now = DateTime.Now;
                if ((now - lastDecodeTime).TotalMilliseconds < MIN_DECODE_INTERVAL)
                {
                    return;
                }

                // 尝试识别条码
                var result = barcodeReader.Decode(frame);




                if (result != null && !string.IsNullOrEmpty(result.Text))
                {
                    // 更新最后识别时间
                    lastDecodeTime = now;

                    // 在UI线程更新结果
                    this.Invoke((MethodInvoker)delegate
                    {
                        txtBarcode.Text = result.Text;
                        System.Media.SystemSounds.Beep.Play();
                        lblStatus.Text = "条码已识别";
                        lblStatus.ForeColor = Color.Green;

                        /* // 输出条码
                       MessageBox.Show($"识别到条码: {result.Text}");*/
                        // 触发条码识别事件
                        textBox_Tag.Text = result.Text; //识别到的码赋值给 textBox_Tag
                        /* input_SensorID1.Text = "test01";
                         input_SensorID2.Text = "test02";*/

                        // 播放提示音
                        System.Media.SystemSounds.Beep.Play();

                        OnBarcodeScanned(result.Text);
                    });
                }
            }
            catch (Exception ex)
            {
                // MessageBox.Show($"条码识别出错: {ex.Message}");
                //初始化提示信息
                button_ShowMess_Mes(AntdUI.TTypeMini.Error, "条码识别出错");
                Console.Write($"条码识别出错: {ex.Message}");
            }
            finally
            {
                // 标记处理完成
                isProcessingFrame = false;
            }
        }



        /// <summary>
        /// 释放所有资源
        /// </summary>
        private void ReleaseResources()
        {
            // 释放PictureBox中的图像资源
            if (pbCamera.Image != null)
            {
                var img = pbCamera.Image;
                pbCamera.Image = null;
                img.Dispose();
            }
            // 释放处理帧
            if (lastProcessedFrame != null)
            {
                lastProcessedFrame.Dispose();
                lastProcessedFrame = null;
            }
            // 释放取消令牌源
            if (formClosingCts != null)
            {
                try
                {
                    formClosingCts.Dispose();
                }
                catch { }
                formClosingCts = null;
            }
        }

        /// <summary>
        /// 在UI线程显示错误
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="eventArgs"></param>
        private void VideoSource_VideoSourceError(object sender, VideoSourceErrorEventArgs eventArgs)
        {
            /*// 在UI线程显示错误
            this.Invoke((MethodInvoker)delegate
            {
                MessageBox.Show($"视频源错误: {eventArgs.Description}",
                                "摄像头错误",
                                MessageBoxButtons.OK,
                                MessageBoxIcon.Error);
                StopCamera();
            });*/
            // 在UI线程显示错误
            if (this.IsDisposed || formClosingCts?.IsCancellationRequested == true) return;

            this.Invoke((MethodInvoker)delegate
            {
                if (!this.IsDisposed)
                {
                    MessageBox.Show($"视频源错误: {eventArgs.Description}",
                                    "摄像头错误",
                                    MessageBoxButtons.OK,
                                    MessageBoxIcon.Error);
                    _ = StopCameraAsync();
                }
            });
        }

        /// <summary>
        /// 异步停止摄像头
        /// </summary>
        /// <returns></returns>
        private async Task StopCameraAsync()
        {
            // 如果没有摄像头或正在停止，直接返回
            if (videoSource == null) return;

            isStopping = true; // 设置停止标志

            try
            {
                // 发出停止信号
                videoSource.SignalToStop();

                // 异步等待停止完成
                await Task.Run(() =>
                {
                    // 等待摄像头停止（最大等待2秒）
                    //int maxWait = 20; // 20 * 100ms = 2秒
                    int maxWait = 10; // 最大等待1秒
                    while (videoSource.IsRunning && maxWait-- > 0)
                    {
                        Thread.Sleep(100);
                    }
                    // 如果仍未停止，强制停止
                    if (videoSource.IsRunning)
                    {
                        videoSource.Stop();
                    }
                });

                // 注销事件处理程序
                if (videoSource != null)
                {
                    videoSource.NewFrame -= VideoSource_NewFrame;
                    videoSource.VideoSourceError -= VideoSource_VideoSourceError;
                }

                if (!this.IsDisposed)
                {
                    // 更新UI状态
                    lblStatus.Text = "已停止";
                    lblStatus.ForeColor = Color.Black;
                    btn_cam_stop.Enabled = false;
                    btn_cam_start.Enabled = true;

                    // 停止后显示提示图像
                    ShowPlaceholderImage();
                }


                // 释放资源
                videoSource = null;
            }
            catch (Exception ex)
            {

                if (!this.IsDisposed)
                {
                    MessageBox.Show($"停止摄像头时出错: {ex.Message}", "错误",
                                    MessageBoxButtons.OK, MessageBoxIcon.Error);
                }


            }

            finally
            {
                isStopping = false; // 清除停止标志
                // 清理处理帧
                if (lastProcessedFrame != null)
                {
                    lastProcessedFrame.Dispose();
                    lastProcessedFrame = null;
                }
                btn_cam_stop.Enabled = false;
                btn_cam_start.Enabled = true;
            }
        }


        /// <summary>
        /// 显示居中提示图像
        /// </summary>
        private void ShowPlaceholderImage()
        {
            if (pbCamera.IsDisposed || this.IsDisposed) return;

            if (pbCamera.Image != null)
            {
                pbCamera.Image.Dispose();
                pbCamera.Image = null;
            }

            try
            {
                // 创建提示图像
                Bitmap placeholder = new Bitmap(pbCamera.Width, pbCamera.Height);

                using (Graphics g = Graphics.FromImage(placeholder))
                {
                    g.Clear(Color.Black);

                    // 绘制摄像头图标
                    using (Font font = new Font("Arial", 24, FontStyle.Bold))
                    using (Brush brush = new SolidBrush(Color.White))
                    {
                        string text = "摄像头已停止";
                        SizeF textSize = g.MeasureString(text, font);

                        float x = (pbCamera.Width - textSize.Width) / 2;
                        float y = (pbCamera.Height - textSize.Height) / 2;

                        g.DrawString(text, font, brush, x, y);
                    }
                }

                pbCamera.Image = placeholder;
            }
            catch (Exception ex)
            {
                MessageBox.Show($"创建提示图像时出错: {ex.Message}");
            }
        }

        /// <summary>
        /// 窗体大小改变时重新居中图像
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_Resize(object sender, EventArgs e)
        {
            // 仅当摄像头运行时才处理图像居中
            if (videoSource != null && videoSource.IsRunning &&
                pbCamera.Image != null && !pbCamera.IsDisposed)
            {
                try
                {
                    // 重新创建居中图像
                    Bitmap currentImage = (Bitmap)pbCamera.Image.Clone();
                    Bitmap centered = CreateCenteredImage(currentImage, pbCamera.Size);

                    pbCamera.Image.Dispose();
                    pbCamera.Image = centered;
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"调整大小时出错: {ex.Message}");
                }
            }

        }

        /// <summary>
        /// 创建居中显示的图像
        /// </summary>
        /// <param name="source"></param>
        /// <param name="containerSize"></param>
        /// <returns></returns>
        private Bitmap CreateCenteredImage(Bitmap source, Size containerSize)
        {
            // 创建一个新的位图作为容器
            Bitmap result = new Bitmap(containerSize.Width, containerSize.Height);

            using (Graphics g = Graphics.FromImage(result))
            {
                // 设置中等质量插值模式以平衡性能和质量
                /* g.InterpolationMode = InterpolationMode.Bilinear;
                 g.SmoothingMode = SmoothingMode.HighSpeed;
                 g.PixelOffsetMode = PixelOffsetMode.HighSpeed;
                 g.CompositingQuality = CompositingQuality.HighSpeed;*/

                // 填充黑色背景
                g.Clear(Color.Black);

                // 计算居中位置
                float ratio = Math.Min(
                    (float)containerSize.Width / source.Width,
                    (float)containerSize.Height / source.Height
                );

                int newWidth = (int)(source.Width * ratio);
                int newHeight = (int)(source.Height * ratio);

                int x = (containerSize.Width - newWidth) / 2;
                int y = (containerSize.Height - newHeight) / 2;

                // 绘制居中图像
                g.DrawImage(source, x, y, newWidth, newHeight);
            }

            return result;
        }

        /// <summary>
        /// 选择最低分辨率
        /// </summary>
        /// <param name="capabilities"></param>
        /// <returns></returns>
        private VideoCapabilities SelectLowestResolution(VideoCapabilities[] capabilities)
        {
            VideoCapabilities lowest = null;
            foreach (var cap in capabilities)
            {
                if (lowest == null ||
                    cap.FrameSize.Width * cap.FrameSize.Height <
                    lowest.FrameSize.Width * lowest.FrameSize.Height)
                {
                    lowest = cap;
                }
            }
            return lowest;
        }

        /// <summary>
        /// 选择较低分辨率以提高性能
        /// </summary>
        /// <param name="capabilities"></param>
        /// <returns></returns>
        private VideoCapabilities SelectLowResolution(VideoCapabilities[] capabilities)
        {
            // 优先选择640x480或更低的
            foreach (var cap in capabilities)
            {
                if (cap.FrameSize.Width <= 640 && cap.FrameSize.Height <= 480)
                {
                    return cap;
                }
            }

            // 否则选择最低分辨率
            return SelectLowestResolution(capabilities);
        }

        /// <summary>
        /// 在应用启动时添加定时清理任务
        /// </summary>
        private static void ScheduleLogCleanup()
        {
            // 每天凌晨2点清理日志
            var cleanupTime = DateTime.Today.AddDays(1).AddHours(2);
            var interval = cleanupTime - DateTime.Now;

            if (interval < TimeSpan.Zero)
                interval = interval.Add(TimeSpan.FromDays(1));

            var timer = new System.Timers.Timer(interval.TotalMilliseconds);
            timer.AutoReset = true;
            timer.Elapsed += (s, e) => CleanupLogs();
            timer.Start();
        }
        /// <summary>
        ///  保留最近30天的日志
        /// </summary>
        private static void CleanupLogs()
        {
            try
            {
                // 保留最近30天的日志
                var cutoffDate = DateTime.Now.AddDays(-30);
                var logDir = new DirectoryInfo(Log4.BaseLogDirectory);

                foreach (var file in logDir.GetFiles("*", SearchOption.AllDirectories))
                {
                    if (file.LastWriteTime < cutoffDate)
                    {
                        file.Delete();
                    }
                }
            }
            catch (Exception ex)
            {
                Log4.Error("System/Maintenance.log", $"日志清理失败: {ex.Message}");
            }
        }
        /// <summary>
        /// 磁盘空间监控
        /// </summary>
        private static void CheckDiskSpace()
        {
            try
            {
                var drive = new DriveInfo(Path.GetPathRoot(Log4.BaseLogDirectory));
                if (drive.AvailableFreeSpace < 100 * 1024 * 1024) // 100MB
                {
                    Log4.Warn("System/Disk.log",
                        $"磁盘空间不足: {drive.AvailableFreeSpace / 1024 / 1024}MB 剩余");
                    Log4.Info("System/Startup", $"磁盘空间不足: {drive.AvailableFreeSpace / 1024 / 1024}MB 剩余");
                    Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"磁盘空间不足: {drive.AvailableFreeSpace / 1024 / 1024}MB 剩余");
                }
            }
            catch
            {
                // 忽略磁盘检查错误
            }
        }
        #endregion


        #region 感应器编码

        /// <summary>
        /// （修复空数据UI更新）根据有效ID数量，安全更新UI（空数据时主动清空）
        /// 核心：解决“无数据时旧值残留”问题
        /// 添加旧值检测，避免重复识别
        /// </summary>
        /// <param name="validSensorIds"></param>
        private void UpdateSensorUI(List<string> validSensorIds)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new Action<List<string>>(UpdateSensorUI), validSensorIds);
                return;
            }

            // 场景1：无有效ID
            if (validSensorIds == null || validSensorIds.Count == 0)
            {
                ClearForm1OldData();
                Console.WriteLine("[Form1-UI更新] 无有效ID，清空input_SensorID1/2");
                return;
            }

            // 场景3：2个有效ID
            if (validSensorIds.Count == 2)
            {
                // 简化的重复检测：比较新旧ID集合
                var newSet = new HashSet<string>(validSensorIds);
                var oldSet = new HashSet<string> { input_SensorID1.Text, input_SensorID2.Text };

                // 如果不是重复识别，则更新UI
                if (!newSet.SetEquals(oldSet))
                {
                    input_SensorID1.Text = validSensorIds[0];
                    input_SensorID2.Text = validSensorIds[1];
                    Console.WriteLine($"[Form1-UI更新] 2个有效ID，input_SensorID1：{validSensorIds[0]}，input_SensorID2：{validSensorIds[1]}");

                    //初始化提示信息
                    button_ShowMess_Mes(AntdUI.TTypeMini.Default, $"识别到最新的FID信息ID1：{validSensorIds[0]}，ID2：{validSensorIds[1]}！");
                    // 新识别，继续业务逻辑
                }
                else
                {
                    Console.WriteLine("[Form1-重复识别] 检测到重复ID组合，停止处理");


                    //初始化提示信息
                    button_ShowMess_Mes(AntdUI.TTypeMini.Default, $"识别到旧数据，FID信息ID1：{validSensorIds[0]}，ID2：{validSensorIds[1]}！");

                    // 重复识别，停止后续处理


                }
            }
        }

        /// <summary>
        /// 核心：HFReader的DataUpdated事件处理方法（保留你原有所有业务逻辑）
        /// 修复点：1. 空数据时主动清空UI；2. 确保原有HandleSensorCodes执行；3. 加日志追踪链路
        /// </summary>
        private void OnForm2DataUpdated(string receivedData)
        {
            // 1. 跨线程安全校验（保留你的原有逻辑，确保UI操作安全）
            if (this.InvokeRequired)
            {
                this.Invoke(new Action<string>(OnForm2DataUpdated), receivedData);
                return;
            }

            // 2. （新增）日志追踪：明确接收的数据内容（便于排查“是否收到空数据”）
            Console.WriteLine($"[Form1-数据接收] 原始推送数据：{receivedData ?? "null/空字符串"}");

            // 3. （核心修复）提取有效传感器ID（与HFReader内部规则对齐，避免无效数据干扰）
            List<string> validSensorIds = ExtractValidSensorIds(receivedData);

            // 4. （核心）根据有效ID数量，同步更新UI（空数据/无有效ID时主动清空）
            UpdateSensorUI(validSensorIds);

            // 5. 保留你的原有业务逻辑（不修改，确保HandleSensorCodes正常执行）
            // 注意：传入“有效ID拼接的字符串”，而非原始空数据（避免无效字符）
            string dataToProcess = validSensorIds.Count > 0
                ? string.Join("|", validSensorIds)
                : string.Empty; // 无有效ID时传空字符串，触发清空逻辑
            HandleSensorCodes(dataToProcess);
            Console.WriteLine($"[Form1-业务触发] 调用HandleSensorCodes，传入数据：{dataToProcess}");
        }
        /// <summary>
        /// 辅助方法：从原始推送数据中提取有效传感器ID（复用HFReader的解析规则）
        /// 作用：统一解析逻辑，确保“HFReader认为的有效ID”与“Form1显示的有效ID”一致
        /// （与HFReader内部对齐）提取有效传感器ID（规则完全同步HFReader内部）
        /// 核心：确保外部解析规则与HFReader内部一致，避免“内部有效外部无效”
        /// </summary>
        private List<string> ExtractValidSensorIds(string rawData)
        {
            List<string> validIds = new List<string>();
            if (string.IsNullOrWhiteSpace(rawData))
            {
                Console.WriteLine("[Form1-解析] 原始数据为空，返回空列表（用于清空UI）");
                return validIds; // 空数据时返回空列表，触发UI清空
            }

            // 步骤1：清理原始数据（与HFReader内部清理规则完全一致：移除空格、分号等干扰字符）
            string cleanedData = Regex.Replace(rawData, @"[\s;,]+", "");
            Console.WriteLine($"[Form1-数据清理] 清理后的数据：{cleanedData}");

            // 步骤2：匹配有效ID（使用与HFReader内部相同的正则，忽略大小写）
            MatchCollection matches = Regex.Matches(cleanedData, SensorIdPattern, RegexOptions.IgnoreCase);
            Console.WriteLine($"[Form1-解析] 匹配到{matches.Count}个符合规则的ID");

            // 步骤3：提取最多2个有效ID（与HFReader内部“最多2个传感器”逻辑对齐）
            foreach (Match match in matches)
            {
                if (validIds.Count < 2)
                {
                    string sensorId = match.Value.ToUpperInvariant(); // 统一转为大写（内外一致）
                    validIds.Add(sensorId);
                    Console.WriteLine($"[Form1-有效ID] 新增：{sensorId}，当前列表：{string.Join("|", validIds)}");
                }
                else
                {
                    Console.WriteLine($"[Form1-解析] ID数量超2个，忽略多余ID：{match.Value}");
                    break;
                }
            }

            return validIds;
        }

        /// <summary>
        /// （修复空数据UI更新）根据有效ID数量，安全更新UI（空数据时主动清空）
        /// 核心：解决“无数据时旧值残留”问题
        /// </summary>
        private void UpdateSensorUI_Last(List<string> validSensorIds)
        {
            // 确保在UI线程操作控件（保留你的跨线程判断逻辑）
            if (this.InvokeRequired)
            {
                this.Invoke(new Action<List<string>>(UpdateSensorUI_Last), validSensorIds);
                return;
            }

            // 场景1：无有效ID（空数据/无匹配）→ 清空所有UI控件，避免旧值残留
            if (validSensorIds == null || validSensorIds.Count == 0)
            {
                /*// 清空你需要操作的UI控件（示例：input_SensorID1/2）
                input_SensorID1.Text = string.Empty;
                input_SensorID2.Text = string.Empty;*/
                ClearForm1OldData();
                Console.WriteLine("[Form1-UI更新] 无有效ID，清空input_SensorID1/2");
                return;
            }

            /*// 场景2：1个有效ID→填充第一个文本框，清空第二个（避免旧值残留）
            if (validSensorIds.Count == 1)
            {
                input_SensorID1.Text = validSensorIds[0];
                input_SensorID2.Text = string.Empty; // 关键：清空第二个文本框旧值
                Console.WriteLine($"[Form1-UI更新] 1个有效ID，input_SensorID1：{validSensorIds[0]}，清空input_SensorID2");
            }*/

            // 场景3：2个有效ID→分别填充两个文本框
            if (validSensorIds.Count == 2 && ((lastsensorid1 != input_SensorID1.Text && lastsensorid2 != input_SensorID2.Text) || (lastsensorid2 != input_SensorID1.Text && lastsensorid1 != input_SensorID2.Text)))
            {
                input_SensorID1.Text = validSensorIds[0];
                input_SensorID2.Text = validSensorIds[1];
                Console.WriteLine($"[Form1-UI更新] 2个有效ID，input_SensorID1：{validSensorIds[0]}，input_SensorID2：{validSensorIds[1]}");
            }
        }

      

        /// <summary>
        /// 统一清理Form1旧数据的方法（空数据/Form2关闭/隐藏时调用）
        /// 核心：确保无有效数据时，彻底清空UI和变量旧值
        /// </summary>
        private void ClearForm1OldData()
        {
            // 1. 清空UI控件旧值（覆盖所有显示传感器数据的控件）
            input_SensorID1.Text = string.Empty;
            input_SensorID2.Text = string.Empty;

            // 2. 清空存储数据的变量（若有保存数据的全局变量，此处一并清空）
            // 示例：若你有全局变量存储数据，需在此清空
            // _savedSensorData = string.Empty;
            // _tempSensorId = string.Empty;

            // 3. （可选）重置业务状态（如标记“无数据”）
            Console.WriteLine("[Form1-清理] 已清空UI旧数据和变量旧值");
        }



        /// <summary>
        /// 处理返回的感应器编码
        /// </summary>
        /// <param name="codes"></param>
        private void HandleSensorCodes(string codes)
        {
            if (codes.Length == 0)
            {

                //初始化提示信息
                button_ShowMess_Mes(AntdUI.TTypeMini.Error, "未识别到任何感应器");
                Console.WriteLine("EClotheForms:未识别到任何感应器");
                return;
            }
            else
            {
                /* string message = $"识别到{codes.Length}个感应器:\n";
                 foreach (var code in codes)
                 {
                     message += $"- {code}\n";
                 }*/
                ParseSensorDatas(codes);

                // 在这里可以根据实际需求处理这些编码
                // 例如：更新UI、保存到数据库等
            }
        }
        /// <summary>
        /// 解析原始数据，提取有效感应器ID（E开头16位）
        /// </summary>
        /// <param name="rawData"></param>
        /// <returns></returns>
        private List<string> ParseSensorDatas(string rawData)
        {
            List<string> sensors = new List<string>();
            if (string.IsNullOrWhiteSpace(rawData)) return sensors;

            // 清理空白字符
            string cleaned = Regex.Replace(rawData, @"\s+", "");
            // 匹配E开头的16位字符串（E+15位0-9/A-F）
            MatchCollection matches = Regex.Matches(cleaned, @"E[0-9A-F]{15}");

            // 提取前2个有效数据
            foreach (Match m in matches)
            {
                if (sensors.Count < 2)
                {
                    sensors.Add(m.Value);

                }
                else break;
            }


            if (sensors.Count == 0)
            {

            }
            if (sensors.Count == 1)
            {

                input_SensorID1.Text = sensors[0];

            }

            else
            {
                input_SensorID1.Text = sensors[0];
                input_SensorID2.Text = sensors[1];
                //MessageBox.Show("识别前2:" + sensors.Count + " ，识别后：[" + input_SensorID1.Text + "][" + input_SensorID2.Text + "]");

            }
            return sensors;
        }





        #endregion

        #region 数据插入/更新/删除
        /// <summary>
        /// 数据 插入数据到 Tb_Clothes
        /// </summary>
        public void In_Tb_Clothes()
        {


            string sql = string.Empty;
            string newGuid = Guid.NewGuid().ToString();
            #region 创建 数据库连接

            // 获取全局SqlSugar实例
            var db = SqlSugarHelper.Db;
            #endregion

            #region 插入一条新数据到Tb_Clothes中

            try
            {
                tB_Clothes_GUID = newGuid;
                //Insert 插入一行数据到Tb_Clothes
                var result = db.Insertable(new Tb_Clothes()
                {
                    GUID = tB_Clothes_GUID,
                    TagID = textBox_Tag.Text,
                    SensorID1 = input_SensorID1.Text,
                    SensorID2 = input_SensorID2.Text,
                    CreatedUserID = _userguid,
                    CreatedUserName = _username,
                    CreatedDatetime = DateTime.Now,
                    IsAuditing = "0",

                }).ExecuteReturnIdentity();
                if (result > 0 || result == 0)
                {
                    Log4.Info($"Log4/sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"调试信息：插入Tb_Clothes表：{1}条信息");
                    //MessageBox.Show($"调试信息：插入Tb_Clothes表：{1}条信息");
                    //初始化提示信息
                    button_ShowMess_Mes(AntdUI.TTypeMini.Default, "成功");
                }
                else
                {
                    //MessageBox.Show("插入Tb_Clothes表失败，请重试");
                    //初始化提示信息
                    button_ShowMess_Mes(AntdUI.TTypeMini.Error, "创建数据失败");
                    return;
                }

            }
            catch (Exception ex)
            {

                // MessageBox.Show("插入Tb_Clothes表错误：" + ex.Message);
                //初始化提示信息
                button_ShowMess_Mes(AntdUI.TTypeMini.Error, "创建数据失败");
                // 详细异常日志/错误日志
                Log4.Error("System/Exceptions",
                    $"插入Tb_Clothes表错误: {ex.Message} , 异常详情: {ex} ");
                Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"插入Tb_Clothes表失败: {ex.Message} , 异常详情: {ex} ");
                throw;
            }


            #endregion
        }

        /// <summary>
        /// 删除Tb_Clothes数据，前提插入tb_sensor表数据时失败，需要删除前面刚生成的Tb_Clothes数据
        /// </summary>
        public void Del_Tb_Clothes()
        {

            string sql = string.Empty;
            string newGuid = Guid.NewGuid().ToString();
            #region 创建 数据库连接

            // 获取全局SqlSugar实例
            var db = SqlSugarHelper.Db;

            try
            {
                //Delete
                //删除
                /* var result = db.Deleteable<Tb_Clothes>()
                     .Where(it => it.TagID == textBox_Tag.Text)
                     .Where(it => it.SensorID1 == input_SensorID1.Text)
                     .Where(it => it.SensorID2 == input_SensorID2.Text)
                     .Where(it => it.IsAuditing == 0)
                     .Where(it => it.CreatedUserID == _userguid)
                     .Where(it => it.CreatedUserName == _username)
                     .Where(it => it.GUID == tB_Clothes_GUID)
                     .ExecuteCommand();*/
                var result = db.Deleteable<Tb_Clothes>()
                     .Where(it => it.GUID == tB_Clothes_GUID)
                     .ExecuteCommand();
                if (result > 0 || result == 0)
                {
                    Log4.Info($"Log4/sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"调试信息：删除Tb_Clothes表：{result}条信息");
                    //MessageBox.Show($"调试信息：删除Tb_Clothes表：{result}条信息");
                    //初始化提示信息
                    button_ShowMess_Mes(AntdUI.TTypeMini.Default, "成功");
                }
                else
                {
                    //MessageBox.Show("删除Tb_Clothes表失败，请重试");
                    //初始化提示信息
                    button_ShowMess_Mes(AntdUI.TTypeMini.Error, "失败");
                    Log4.Info($"Log4/sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"调试信息：删除Tb_Clothes表失败：{result}条信息");
                    return;
                }
            }
            catch (Exception ex)
            {
                //MessageBox.Show("删除Tb_Clothes表失败/错误：" + ex.Message);
                //初始化提示信息
                button_ShowMess_Mes(AntdUI.TTypeMini.Error, "失败");
                // 详细异常日志/错误日志
                Log4.Error("System/Exceptions",
                    $"删除Tb_Clothes表失败: {ex.Message} , 异常详情: {ex} ");
                Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"删除Tb_Clothes表失败: {ex.Message} , 异常详情: {ex} ");
                throw;
            }


            #endregion
        }

        /// <summary>
        /// 数据 插入/更新数据到 Tb_Sensor
        /// </summary>
        public void InorUp_Tb_Sensor()
        {
            int count = 0;
            int count1 = 0;
            string sql = string.Empty;
            string newGuid = Guid.NewGuid().ToString();
            #region 创建 数据库连接

            // 获取全局SqlSugar实例
            var db = SqlSugarHelper.Db;
            #endregion

            #region 更新数据到 Tb_Sensor，input_SensorID1

            //条件查询 input_SensorID1
            count = 0;
            count = db.Queryable<Tb_Sensor>()
                .Where(it => it.SensorID == input_SensorID1.Text)
                .Count();
            if (count > 0)
            {
                count1 = 0;
                count1 = db.Queryable<Tb_Sensor>()
                    .Where(it => it.SensorID == input_SensorID1.Text)
                    .Where(it => it.State == 0)
                    .Count();

                if (count1 == 1)
                {
                    try
                    {
                        //指定多个字段更新
                        var result = db.Updateable<Tb_Sensor>()
                       .SetColumns(
                           it => new Tb_Sensor()
                           {
                               ClothesGUID = tB_Clothes_GUID,
                               TagID = textBox_Tag.Text,
                               SensorID = input_SensorID1.Text,
                               Datetime = DateTime.Now,
                               State = 1,

                           }
                       )//类只能在表达示里面不能提取
                       .Where(it => it.SensorID == input_SensorID1.Text)
                       .Where(it => it.State == 0)
                       .ExecuteCommand();   //表达式写2列更新2列，其他不会更新

                        Log4.Info($"Log4/sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"调试信息：更新Tb_Sensor表：{result}条信息,TagID={textBox_Tag.Text},SensorID1 ={input_SensorID1.Text},State = {1},");
                        //MessageBox.Show($"调试信息：更新Tb_Sensor表：{result}条信息,TagID={textBox_Tag.Text},SensorID1 ={input_SensorID1.Text},State = {1},");
                        //初始化提示信息
                        button_ShowMess_Mes(AntdUI.TTypeMini.Default, "成功");
                    }
                    catch (Exception ex)
                    {
                        //插入失败是，需要删除Tb_Clothes表中的数据
                        Del_Tb_Clothes();

                        //MessageBox.Show("更新传感器1数据错误：" + ex.Message);
                        //初始化提示信息
                        button_ShowMess_Mes(AntdUI.TTypeMini.Error, "更新数据错误");
                        // 详细异常日志/错误日志
                        Log4.Error("System/Exceptions",
                            $"更新传感器1数据错误: {ex.Message} , 异常详情: {ex} ");
                        Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"更新传感器1数据错误: {ex.Message} , 异常详情: {ex} ");

                        throw;
                    }

                }
                else if (count1 != 1)
                {
                    //初始化提示信息
                    button_ShowMess_Mes(AntdUI.TTypeMini.Error, $"当前传感器SensorID1[{input_SensorID1.Text}],State状态不符，不能绑定");
                    Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"当前传感器SensorID1：{input_SensorID1.Text}，State状态不符，不能绑定!");
                    return;
                }


            }
            else
            {
                try
                {

                    //Insert 插入一行 input_SensorID1 数据到 Tb_Sensor
                    var result = db.Insertable(new Tb_Sensor()
                    {
                        GUID = Guid.NewGuid().ToString(),
                        ClothesGUID = tB_Clothes_GUID,
                        TagID = textBox_Tag.Text,
                        SensorID = input_SensorID1.Text,
                        Datetime = DateTime.Now,
                        State = 1,

                    }).ExecuteReturnIdentity();

                    if (result > 0 || result == 0)
                    {
                        Log4.Info($"Log4/sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"调试信息：插入Tb_Sensor表：{result}条信息,TagID={textBox_Tag.Text},SensorID1 ={input_SensorID1.Text},State = {1},");
                        // MessageBox.Show($"调试信息：插入Tb_Sensor表：{result}条信息,TagID={textBox_Tag.Text},SensorID1 ={input_SensorID1.Text},State = {1},");
                        //初始化提示信息
                        button_ShowMess_Mes(AntdUI.TTypeMini.Default, "成功");
                    }
                    else
                    {
                        //MessageBox.Show("input_SensorID1插入Tb_Sensor表失败，请重试");
                        //初始化提示信息
                        button_ShowMess_Mes(AntdUI.TTypeMini.Error, "失败");
                        Log4.Info($"Log4/sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"input_SensorID1插入Tb_Sensor表失败，请重试");


                        return;
                    }

                }
                catch (Exception ex)
                {
                    //插入失败是，需要删除Tb_Clothes表中的数据
                    Del_Tb_Clothes();
                    //MessageBox.Show("插入Tb_Sensor，input_SensorID1数据错误：" + ex.Message);
                    //初始化提示信息
                    button_ShowMess_Mes(AntdUI.TTypeMini.Error, "失败");
                    // 详细异常日志/错误日志
                    Log4.Error("System/Exceptions",
                        $"插入Tb_Sensor，input_SensorID1数据错误: {ex.Message} , 异常详情: {ex} ");
                    Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"插入Tb_Sensor，input_SensorID1数据错误: {ex.Message} , 异常详情: {ex} ");
                    throw;
                }

            }

            #endregion 更新数据到 Tb_Sensor，input_SensorID1

            #region 更新数据到 Tb_Sensor，input_SensorID2

            //条件查询 input_SensorID2
            count = 0;
            count = db.Queryable<Tb_Sensor>()
                .Where(it => it.SensorID == input_SensorID2.Text)
                .Count();
            if (count > 0)
            {

                count1 = 0;
                count1 = db.Queryable<Tb_Sensor>()
                    .Where(it => it.SensorID == input_SensorID2.Text)
                    .Where(it => it.State == 0)
                    .Count();

                if (count1 == 1)
                {
                    try
                    {
                        //指定多个字段更新
                        var result = db.Updateable<Tb_Sensor>()
                       .SetColumns(
                           it => new Tb_Sensor()
                           {
                               ClothesGUID = tB_Clothes_GUID,
                               TagID = textBox_Tag.Text,
                               SensorID = input_SensorID2.Text,
                               Datetime = DateTime.Now,
                               State = 1,

                           }
                       )//类只能在表达示里面不能提取
                       .Where(it => it.SensorID == input_SensorID2.Text)
                       .Where(it => it.State == 0)
                       .ExecuteCommand();   //表达式写2列更新2列，其他不会更新

                        Log4.Info($"Log4/sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"调试信息：更新Tb_Sensor表：{result}条信息,TagID={textBox_Tag.Text},SensorID2 ={input_SensorID2.Text},State = {1},");
                        //MessageBox.Show($"调试信息：更新Tb_Sensor表：{result}条信息,TagID={textBox_Tag.Text},SensorID2 ={input_SensorID2.Text},State = {1},");
                        //初始化提示信息
                        button_ShowMess_Mes(AntdUI.TTypeMini.Default, "成功");
                    }
                    catch (Exception ex)
                    {
                        //插入失败是，需要删除Tb_Clothes表中的数据
                        Del_Tb_Clothes();

                        //MessageBox.Show("更新传感器1数据错误：" + ex.Message);
                        //初始化提示信息
                        button_ShowMess_Mes(AntdUI.TTypeMini.Error, "失败");
                        // 详细异常日志/错误日志
                        Log4.Error("System/Exceptions",
                            $"更新传感器1数据错误: {ex.Message} , 异常详情: {ex} ");
                        Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"更新传感器1数据错误: {ex.Message} , 异常详情: {ex} ");

                        throw;
                    }

                }
                else
                {
                    //初始化提示信息
                    button_ShowMess_Mes(AntdUI.TTypeMini.Error, $"当前传感器SensorID2[{input_SensorID2.Text}],State状态不符，不能绑定");
                    Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"当前传感器SensorID1：{input_SensorID2.Text}，State状态不符，不能绑定!");
                    return;
                }



            }
            else
            {
                try
                {

                    //Insert 插入一行 input_SensorID2 数据到 Tb_Sensor
                    var result = db.Insertable(new Tb_Sensor()
                    {
                        GUID = Guid.NewGuid().ToString(),
                        ClothesGUID = tB_Clothes_GUID,
                        TagID = textBox_Tag.Text,
                        SensorID = input_SensorID2.Text,
                        Datetime = DateTime.Now,
                        State = 1,

                    }).ExecuteReturnIdentity();

                    if (result > 0 || result == 0)
                    {
                        Log4.Info($"Log4/sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"调试信息：插入Tb_Sensor表：{result}条信息,TagID={textBox_Tag.Text},SensorID1 ={input_SensorID2.Text},State = {1},");
                        //MessageBox.Show($"调试信息：插入Tb_Sensor表：{result}条信息,TagID={textBox_Tag.Text},SensorID1 ={input_SensorID2.Text},State = {1},");
                        //初始化提示信息
                        button_ShowMess_Mes(AntdUI.TTypeMini.Default, "成功");
                    }
                    else
                    {
                        //MessageBox.Show("input_SensorID2插入Tb_Sensor表失败，请重试");
                        //初始化提示信息
                        button_ShowMess_Mes(AntdUI.TTypeMini.Error, "失败");
                        Log4.Info($"Log4/sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"input_SensorID2插入Tb_Sensor表失败，请重试");


                        return;
                    }

                }
                catch (Exception ex)
                {
                    //插入失败是，需要删除Tb_Clothes表中的数据
                    Del_Tb_Clothes();
                    //MessageBox.Show("插入Tb_Sensor，input_SensorID2数据错误：" + ex.Message);
                    //初始化提示信息
                    button_ShowMess_Mes(AntdUI.TTypeMini.Error, "失败");
                    // 详细异常日志/错误日志
                    Log4.Error("System/Exceptions",
                        $"插入Tb_Sensor，input_SensorID2数据错误: {ex.Message} , 异常详情: {ex} ");
                    Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", $"插入Tb_Sensor，input_SensorID2数据错误: {ex.Message} , 异常详情: {ex} ");
                    throw;
                }

            }

            #endregion 更新数据到 Tb_Sensor，input_SensorID2
        }


        #endregion

        #region 初始化各种信息



        /// <summary>
        /// 自动启动摄像头和读卡器（适配现有代码逻辑，含权限校验、状态管理、日志记录）
        /// 流程：1.权限校验→2.启动摄像头→3.启动读卡器（摄像头启动成功才执行）
        /// 自动启动摄像头和读卡器（仅简单校验，复用现有按钮逻辑）
        /// 简单校验：1.权限（仅admin） 2.设备是否已启动 3.摄像头是否存在
        /// </summary>
        private void AutoStartCamAndRead()
        {
            // 新增：首次以admin运行时，给所有Users组添加摄像头权限（仅执行一次）
            if (_username == "admin" && !File.Exists("CameraPermissionSet.txt"))
            {
                try
                {
                    // 调用CMD给Users组授权摄像头（以admin权限执行）
                    Process.Start(new ProcessStartInfo
                    {
                        FileName = "cmd.exe",
                        Arguments = $"/c icacls \"C:\\Windows\\System32\\Quartz.dll\" /grant \"Users:(R,X)\" /t",
                        Verb = "runas", // 以管理员权限运行
                        CreateNoWindow = true,
                        WindowStyle = ProcessWindowStyle.Hidden
                    }).WaitForExit();
                    File.Create("CameraPermissionSet.txt"); // 标记已执行，避免重复
                }
                catch { }
            }

            // 1. 记录非admin用户启动日志（便于检测）
            string startLog = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 用户[{_username}]：触发自动启动";
            Log4.Info($"Log4/AutoStart/{DateTime.Today:yyyy-MM-dd}.log", startLog);
            Console.WriteLine(startLog);

            // 2. 启动摄像头（复用btn_cam_stop的启动逻辑，无需重复绑定事件）
            if (!isCameraRunning && videoDevices != null && videoDevices.Count > 0)
            {
                try
                {
                    btn_cam_start.PerformClick(); // 代码触发“启动摄像头”按钮事件
                    //Log4.Info($"Log4/AutoStart/{DateTime.Today:yyyy-MM-dd}.log", $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 用户[{_username}]：摄像头启动指令已触发");
                }
                catch (Exception ex)
                {
                    string errLog = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 用户[{_username}]：启动摄像头失败：{ex.Message}";
                    Log4.Error($"Log4/AutoStart/{DateTime.Today:yyyy-MM-dd}.log", errLog);
                    MessageBox.Show(errLog);
                    return; // 摄像头启动失败，不继续启动读卡器
                }
            }
            else if (isCameraRunning)
            {
                Log4.Info($"Log4/AutoStart/{DateTime.Today:yyyy-MM-dd}.log", $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 用户[{_username}]：摄像头已启动，无需重复操作");
            }
            else
            {
                string warnLog = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 用户[{_username}]：无可用摄像头，跳过自动启动";
                Log4.Warn($"Log4/AutoStart/{DateTime.Today:yyyy-MM-dd}.log", warnLog);
                MessageBox.Show(warnLog);
                return;
            }

            // 3. 启动读卡器（复用btn_StartRead的显示逻辑，无需重复绑定事件）
            if (!isReaderRunning)
            {
                try
                {
                    btn_StartRead.PerformClick(); // 代码触发“启动读卡器”按钮事件
                    Log4.Info($"Log4/AutoStart/{DateTime.Today:yyyy-MM-dd}.log", $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 用户[{_username}]：读卡器启动指令已触发");
                }
                catch (Exception ex)
                {
                    string errLog = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 用户[{_username}]：启动读卡器失败：{ex.Message}";
                    Log4.Error($"Log4/AutoStart/{DateTime.Today:yyyy-MM-dd}.log", errLog);
                    MessageBox.Show(errLog);
                }
            }
            else
            {
                Log4.Info($"Log4/AutoStart/{DateTime.Today:yyyy-MM-dd}.log", $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 用户[{_username}]：读卡器已启动，无需重复操作");
            }
        }


        /// <summary>
        /// 加载配置并初始化核心数据（仅修改非admin用户的按钮权限：只隐藏，不禁用）
        /// 核心调整：非admin用户删除「Enabled=false」，仅保留「Visible=false」，确保按钮可通过代码触发事件
        /// </summary>
        private void LoadConfigAndInitData()
        {
            // 1. 加载配置文件（保留原有逻辑：从config.json读取当前用户信息）
            var config = AppConfig.LoadConfig();

            // 2. 初始化用户信息变量（保留原有赋值逻辑，与界面显示、业务逻辑关联）
            LoginUserName = config?.CurrentUser?.UserName ?? "未知用户";
            label_name.Text = config?.CurrentUser?.UserName ?? "未知用户";
            _username = config?.CurrentUser?.UserName ?? "未知用户";
            _userguid = config?.CurrentUser?.UserGuid ?? "未知用户ID";

            // 3. 权限控制：区分admin与非admin用户的按钮状态（仅修改Enabled相关逻辑）
            if (_username != "admin")
            {
                panel_info.Dock = DockStyle.Fill;

            }
            else
            {
                panel_info.Dock = DockStyle.None;
                panel_info.Size = new Size(0, 0);

            }

            // 4. 保留原有日志记录（若后续需要添加，可在此补充，当前按原代码逻辑不新增）
            Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log",
                      $"用户信息初始化完成：用户名={_username}，用户ID={_userguid}");
        }


        /// <summary>
        /// //初始化表格列头 
        /// </summary>
        private void InitTableColumns()
        {

            dataGridView_table.Columns = new ColumnCollection() {
                new Column("","序号"){
                    Width = "50",
                    Fixed = true,//冻结列
                },
                new ColumnCheck("Selected"){Fixed = true},
                new Column("CreatedDatetime", "创建时间",ColumnAlign.Center),
                new Column("IsAuditing", "是否审核",ColumnAlign.Center),
                new Column("TagID", "衣物吊牌",ColumnAlign.Center),
                new Column("SensorID1", "传感器1",ColumnAlign.Center),
                new Column("SensorID2", "传感器2",ColumnAlign.Center),
                new Column("CreatedUserName", "创建人",ColumnAlign.Center),
                new Column("UpDatedUserName", "更新人",ColumnAlign.Center),
                new Column("UpDatedDatetime", "更新时间",ColumnAlign.Center),
                new Column("GUID", "主键",ColumnAlign.Center),
                new Column("CreatedUserID", "创建人ID",ColumnAlign.Center),
                new Column("UpdatedUserID", "更新人ID",ColumnAlign.Center),
                new Column("Ph", "批号",ColumnAlign.Center),


            };


        }

        /// <summary>
        /// 当前用户所关联订单
        /// </summary>
        public void dataGridView_table_data()
        {
            #region 创建 数据库连接，并赋值

            // 获取全局SqlSugar实例
            var db = SqlSugarHelper.Db;

            // 执行查询
            List<Tb_Clothes> list = db.Queryable<Tb_Clothes>()
              //.Where(s => s.CreatedDatetime > DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))
              //.Where(s => SqlFunc.ToDate(s.CreatedDatetime) > DateTime.Now.AddDays(-2))
              //.Where(s => s.CreatedUserID == _userguid)
              .Where(s => s.CreatedUserName == LoginUserName) //label_name.Text
              .Take(1000)
              .OrderByDescending(s => s.CreatedDatetime)
              .ToList();

            antList_userinfo = new AntList<Tb_UsersInfo>();

            // 显示到DataGridView
            dataGridView_table.DataSource = list;


            //设置树数据，可为任意行设置

            //antList[1].Users = subUsers.ToArray();
            //dataGridView_table.Binding(antList_userinfo);


            //设置行禁用
            dataGridView_table.SetRowEnable(0, false, true);

            /*//竖向合并单元格
            dataGridView_table.AddMergedRegion(new CellRange(2, 4, 3, 3));
            //横向合并单元格
            dataGridView_table.AddMergedRegion(new CellRange(5, 5, 1, 3));*/
            // 记录成功日志
            Log4.Info($"Log4/Sqllog/{DateTime.Today.ToString("yyyy-MM-dd")}.log", "初始化成功，加载Tb_Clothes数据");

            #endregion 创建 数据库连接，并赋值
        }

        /// <summary>
        /// 初始化提示按钮 信息
        /// </summary>
        public void button_ShowMess_Mes(AntdUI.TTypeMini type, string mes)
        {
            // 详细异常日志/错误日志
            //button_ShowMess.Type = AntdUI.TTypeMini.Success;
            button_ShowMess.Type = type;
            button_ShowMess.Text = mes;
        }

        /// <summary>
        /// 输入框颜色变频。
        /// </summary>
        /// <param name="type"></param>
        /// <param name="mes"></param>
        public async Task button_BackColor(string str )
        {
            // 匹配对应的输入控件并赋值
            switch (str)
            {
                
                case "input_SensorID1":
                    for (int i = 0; i < 3; i++)
                    {
                        input_SensorID1.BackColor = Color.Red;
                        await Task.Delay(1000);
                        input_SensorID1.BackColor = Color.Transparent;
                    }
                    break;
                case "input_SensorID2":
                    for (int i = 0; i < 3; i++)
                    {
                        input_SensorID2.BackColor = Color.Red;
                        await Task.Delay(1000);
                        input_SensorID2.BackColor = Color.Transparent;
                    }
                    break;
                case "textBox_Tag":
                    for (int i = 0; i < 3; i++)
                    {
                        textBox_Tag.BackColor = Color.Red;
                        await Task.Delay(1000);
                        textBox_Tag.BackColor = Color.Transparent;
                    }
                    break;
               

            }
           
           
        }


        #endregion 初始化各种信息

      
    }
}
